﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace _4委托与事件
{
    class Cat
    {
        private string Name;

        public Cat(string name)
        {
            this.Name = name;
        }
        ///// <summary>
        ///// 声明委托
        ///// </summary>
        //public delegate void CatShoutEventHandler();
        ///// <summary>
        ///// 声明事件
        ///// </summary>
        //public event CatShoutEventHandler CatShout;

        /// <summary>
        /// 声明委托
        /// </summary>
        public delegate void CatShoutEventHandler(object sender, CatShoutEventArgs e);
        /// <summary>
        /// 声明事件
        /// </summary>
        public event CatShoutEventHandler CatShout;

        public void Shout()
        {
            MessageBox.Show("喵，我是" + Name);
            if (CatShout != null)
            {
                CatShoutEventArgs e = new CatShoutEventArgs();
                e.Name = this.Name;
                CatShout(this, e);
            }
        }
    }

    class Mouse
    {
        private string Name;

        public Mouse(string name)
        {
            this.Name = name;
        }

        public void Run(object sender, CatShoutEventArgs e)
        {
            MessageBox.Show("老猫" + e.Name + "来了，" + Name + "快跑");
        }
    }

    public class CatShoutEventArgs : EventArgs
    {
        private string name;
        public string Name
        {
            get { return name; }
            set { name = value; }
        }
    }




    //新的例子
    /// <summary>
    /// 定义一个委托，委托是一种用户自定义的数据类型，可以用于定义变量
    /// </summary>
    /// <param name="value1">参数1</param>
    /// <param name="value2">参数2</param>
    /// <returns></returns>
    public delegate int MathOptDelgate(int value1, int value2);
    class MathOpt
    {
        public int Add(int x, int y)
        {
            return x + y;
        }
        public static int Max(int x, int y)
        {
            return (x >= y) ? x : y;
        }
    }
    class Use
    {
        public void UseTest()
        {
            //委托是一种用户自定义的数据类型，可以用于定义变量
            MathOptDelgate oppDel;
            //委托变量可以接收一个实例方法引用
            MathOpt obj = new MathOpt();
            oppDel = obj.Add;
            //也可以接收一个静态方法引用
            oppDel = MathOpt.Max;
            //委托变量可以当成普通方法那样调用
            var max = oppDel(1, 4);
            //可以定义委托类型的参数，可以把方法引用直接传给委托类型的参数
            var add = UseDelegate(obj.Add, 12, 20);
            var max1 = UseDelegate(MathOpt.Max, 12, 30);


            oppDel += obj.Add;
            Delegate[] list = oppDel.GetInvocationList();
        }
        /// <summary>
        /// 可以定义委托类型的参数
        /// </summary>
        /// <param name="option">委托类型参数</param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public int UseDelegate(MathOptDelgate option, int x, int y)
        {
            return option(x, y);
        }
    }
}
/// <summary>
/// 新的委托和事件
/// </summary>
namespace SimpleEvent
{
    public class EventTest
    {
        private int value;

        public delegate void NumManipulationHandler();

        public event NumManipulationHandler ChangeNum;

        protected virtual void OnNumChanged()
        {
            if (ChangeNum != null)
            {
                ChangeNum();
            }
            else
            {
                //事件触发的情况
                MessageBox.Show("事件触发");
            }
        }

        public EventTest(int n)
        {
            SetValue(n);
        }

        public void SetValue(int n)
        {
            if (value != n)
            {
                value = n;
                OnNumChanged();
            }
        }
    }

    public class MainClass
    {
        public static void TaskTest()
        {
            Func<int, int, int> fi = (str, str2) => { return str + str2; };
            Task taskAction = new Task((() => { }));//无入参匿名Action
            taskAction.Start();
            Task<int> taskFunc = new Task<int>((() => { return 1; }));//无入参匿名Func
            taskFunc.Start();
            int result = taskFunc.GetAwaiter().GetResult();//获取线程返回结果

            Action action = new Action((() => { }));
            IAsyncResult result1 = action.BeginInvoke((iar) => { }, null);

            Func<int> func = new Func<int>(() => { return 1; });
            IAsyncResult resultfunc = func.BeginInvoke((iar) =>
            {
                var res = func.EndInvoke(iar);
            }, null);
        }
    }
    #region 委托-第一核心应用——随手线程：
    //我们在做开发的时候，一定接触过父类。父类是干什么的呢？父类通常是用来编写公共属性和函数，方便子类调用的。
    //  那我们的委托的第一个核心应用，就是父类的公共函数，线程随手启动。如何随手开启呢？
    // 首先，我们创建父类代码如下：
    class BaseDelegateSyntax
    {
        public void AsyncLoad(Action action)
        {

        }
        public void AsyncLoad(Action action, Action callback)
        {
            IAsyncResult result = action.BeginInvoke((iar) =>
            {
                callback();
            }, null);
        }
        public void AsyncLoad<T>(Action<T> action, T para, Action callback)
        {
            IAsyncResult result = action.BeginInvoke(para, (iar) =>
            {
                callback();
            }, null);
        }
        public void AsyncLoad<T, R>(Func<T, R> action, T para, Action<R> callback)
        {
            IAsyncResult result = action.BeginInvoke(para, (iar) =>
            {
                var res = action.EndInvoke(iar);
                callback(res);
            }, null);
        }

        public void Test(string a, int d, out Tuple<int, string> dd)
        {
            dd = new Tuple<int, string>(1, "ddd");

        }
    }
    //我们看到上面的代码，父类中添加了四个异步委托的调用函数，接下来，我们就可以在继承该类的子类中，随手开启线程了。
    // 子类代码如下：
    class ChildDelegateSyntax : BaseDelegateSyntax
    {
        public void Excute()
        {
            //开启异步方法
            base.AsyncLoad(() => { });

            //开启异步方法，并且在异步结束后，触发回调方法
            base.AsyncLoad(() => { },
                () =>
                {
                    //我是回调方法
                });

            //开启异步有入参的方法，传递参数，并且在异步结束后，触发回调方法
            base.AsyncLoad<string>((s) => { }, "Kiba518",
                () =>
                {
                    //我是回调方法
                });

            //开启异步有入参的方法，传递字符串参数Kiba518，之后返回int型结果518，
            //并且在异步结束后，触发回调方法，回调函数中可以获得结果518
            base.AsyncLoad<string, int>((s) =>
            {
                return 518;
            }, "Kiba518",
                (result) =>
                {
                    //我是回调方法 result是返回值518
                });
        }
    }
    #endregion
    #region 委托-第二核心应用——穿越你的世界
    //接下来，我们来看委托的第二种核心用法，穿越的应用。

    //这个应用，是最常见，也最普通的应用了。因为委托是引用类型，所以A类里定义的委托，可以在被内存回收之前，被其他类调用。

    //我们经常会在各种论坛看到有人发问，A页面如何调用B页面的属性、方法、父页面获取子页面的属性、方法，或者子页面获取父页面的属性、方法。

    // 其实，只要定义好委托，并将委托正确的传递，就可以实现穿越的调用了。

    // 下面我们看下穿越应用的代码。
    public class FirstDelegateSyntax
    {
        public FirstDelegateSyntax()
        {
            Console.WriteLine(" First 开始 ");
            SecondDelegateSyntax sds = new SecondDelegateSyntax(() =>
            {
                Console.WriteLine(" First传给Second委托被触发 ");
            });
            sds.Excute();
            Console.WriteLine(" First 结束 ");
        }
    }

    public class SecondDelegateSyntax
    {
        public Action Action { get; set; }
        public SecondDelegateSyntax(Action _action)
        {
            Console.WriteLine(" Second的构造函数 ");
            Action = _action;
        }
        public void Excute()
        {
            Console.WriteLine(" Second的Excute被触发 ");
            Action();
        }
    }
    #endregion
}